using System;
using Sce.PlayStation.Core;

namespace Nyanimals
{
	public sealed class CCamera
	{
		private static readonly CCamera instance = new CCamera();
		
		Matrix4 localMatrix;
	    Matrix4 projection;
		Matrix4 view;
		Matrix4 target;
		
		float rotationX;
		float rotationY;
	
		public static CCamera Instance
		{
			get { return instance;}
		}
		private CCamera()
		{
			localMatrix = Matrix4.Identity;
			view = Matrix4.Identity.Inverse();
			target = Matrix4.Identity;
			rotationX = 0;
			rotationY = 0;
		}
		
		public Matrix4 LocalMatrix
		{
			get { return localMatrix;}
			set { localMatrix = value;}
		}
		public Matrix4 Target
		{
			get { return target;}
			set { target = value;}
		}
		
	    public void BuildPerspective( float fov, float aspect, float near, float far )
	    {
	        projection = Matrix4.Perspective( fov, aspect, near, far );
	
	        localMatrix = Matrix4.Identity;
		}	                    
	    public Matrix4 Projection
	    {
	        get{ return projection; }
		}
		public Matrix4 View
		{
			get
			{ 
				return view;
			}
		}
		
		public void Rotate()
		{
			// the two rotation matrices
			Matrix4 rotX = Matrix4.RotationX(FMath.Radians(rotationX));
			Matrix4 rotY = Matrix4.RotationY(FMath.Radians(rotationY));
			
			// targets coordinate system
			Matrix4 targetInv = target.Inverse();
			
			// put the camera in the target coordinate system
			Matrix4 localCam = targetInv * localMatrix;
			
			// get the cameras rotation and translation
			Matrix4 camRotation = localCam;
			camRotation.AxisW = Vector3.Zero;
			
			Matrix4 camRotationInv = camRotation.Inverse();
			
			// camera = rotation * translation
			// so: translation = rotation^-1 * camera
			Matrix4 camTranslation = camRotationInv * localCam;
			
			// rebuild
			localMatrix = target * rotY * camRotation * rotX * camTranslation;
			
			// update the view
			view = localMatrix.Inverse();
		}
		
		public void SetRotation(float degX, float degY)
		{
			rotationX = degX;
			rotationY = degY;
		}
		public void IncreaseRotation(float degX, float degY)
		{
			rotationX += degX;
			rotationY += degY;
			
			// update the X
			if(rotationX > 360)
				rotationX -= 360;
			if(rotationX < 0)
				rotationX += 360;
			
			// update hte Y
			if(rotationY > 360)
				rotationY -= 360;
			if(rotationY < 0)
				rotationY += 360;
		}
		
		public void Update(float deltaTime)
		{
			Vector3 position = target.AxisW;
			
			// the two rotation matrices
			Matrix4 rotX = Matrix4.RotationX(FMath.Radians(rotationX));
			Matrix4 rotY = Matrix4.RotationY(FMath.Radians(rotationY));
			
			// start building the new view matrix
			Matrix4 finalMat = rotY * rotX; // NOTE: might need flipped...
			
			// our dist from the player
			Vector3 axisZ = finalMat.AxisZ;
			axisZ = axisZ.Normalize();
			axisZ = axisZ * -15.0f;
			
			// our translation
			Matrix4 translation = Matrix4.Translation(axisZ + position);
			finalMat = translation * finalMat; // NOTE: might need flipped
			
			// rotate 180 degs to align
			Matrix4 rotMatY = Matrix4.RotationAxis(finalMat.AxisY, FMath.Radians(180.0f));
			
			// hold hte current position and set back to origin
			Vector3 tempPos = finalMat.AxisW;
			finalMat.AxisW = Vector3.Zero;
			
			// rotate and move back
			finalMat = rotMatY * finalMat; // NOTE: might need flipped
			finalMat.AxisW = tempPos;
			
			localMatrix = finalMat;
			
			// build the view matrix
			Matrix4 tempRotation = finalMat;
			tempRotation.AxisW = Vector3.Zero;
			tempRotation = tempRotation.Transpose();
			
			Matrix4 tempTransform = Matrix4.Identity;
			tempTransform.AxisW = -finalMat.AxisW;
			
			view = tempRotation * tempTransform;
		}
		
	}
}

